home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / leavembox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-31  |  28.2 KB  |  939 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: leavembox.c,v 5.17 1993/05/31 19:47:45 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.17 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: leavembox.c,v $
  17.  * Revision 5.17  1993/05/31  19:47:45  syd
  18.  * change is_symlink to no_restore and use it for special modes as well
  19.  * From: Syd
  20.  *
  21.  * Revision 5.16  1993/05/31  19:44:46  syd
  22.  * If 'enforcement' modes set, use copy not link
  23.  *
  24.  * Revision 5.15  1993/05/08  20:25:33  syd
  25.  * Add sleepmsg to control transient message delays
  26.  * From: Syd
  27.  *
  28.  * Revision 5.14  1993/04/12  02:34:36  syd
  29.  * I have now added a parameter which controls whether want_to clears the
  30.  * line and centers the question or behaves like it did before. I also
  31.  * added a 0 at the end of the parameter list to all the other calls to
  32.  * want_to where a centered question on a clean line is not desirable.
  33.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  34.  *
  35.  * Revision 5.13  1993/02/03  17:12:53  syd
  36.  * move more declarations to defs.h, including sleep
  37.  * From: Syd
  38.  *
  39.  * Revision 5.12  1993/01/27  20:43:26  syd
  40.  * The following minor patch for leavembox.c is useful for BSD systems
  41.  * which implement correct (per SVID & POSIX) struct utimbuf.  Where the
  42.  * source previously tested just '#ifdef BSD' it now tests '#if
  43.  * defined(BSD) && !defined(UTIMBUF)'.  This suppresses a compile-time
  44.  * warning on ConvexOS due to the prototype of utime.
  45.  * From: rwright@dhostwo.convex.com (Randy Wright)
  46.  *
  47.  * Revision 5.11  1993/01/20  03:08:43  syd
  48.  * alter the message on aborts to report the temp file name to the user
  49.  * From: The Postmaster <sysnet@central1.lancaster.ac.uk>
  50.  *
  51.  * Revision 5.10  1993/01/20  03:02:19  syd
  52.  * Move string declarations to defs.h
  53.  * From: Syd
  54.  *
  55.  * Revision 5.9  1992/12/24  21:58:52  syd
  56.  * Add lstat call to properly detect symlink
  57.  * From: Syd via partial patch from Bryan Curnutt
  58.  *
  59.  * Revision 5.8  1992/12/24  21:42:01  syd
  60.  * Fix messages and nls messages to match.  Plus use want_to
  61.  * where appropriate.
  62.  * From: Syd, via prompting from Jan Djarv <Jan.Djarv@sa.erisoft.se>
  63.  *
  64.  * Revision 5.7  1992/12/11  01:45:04  syd
  65.  * remove sys/types.h include, it is now included by defs.h
  66.  * and this routine includes defs.h or indirectly includes defs.h
  67.  * From: Syd
  68.  *
  69.  * Revision 5.6  1992/12/07  03:49:49  syd
  70.  * use BSD or not apollo on file.h include as its not valid
  71.  * for Apollos under sys5.3 compile type
  72.  * From: gordonb@mcil.comm.mot.com (Gordon Berkley)
  73.  *
  74.  * Revision 5.5  1992/11/26  01:46:26  syd
  75.  * add Decode option to copy_message, convert copy_message to
  76.  * use bit or for options.
  77.  * From: Syd and bjoerns@stud.cs.uit.no (Bjoern Stabell)
  78.  *
  79.  * Revision 5.4  1992/11/26  00:46:13  syd
  80.  * changes to first change screen back (Raw off) and then issue final
  81.  * error message.
  82.  * From: Syd
  83.  *
  84.  * Revision 5.3  1992/10/27  01:52:16  syd
  85.  * Always include <sys/ioctl.h> in curses.c When calling ioctl()
  86.  *
  87.  * Remove declaration of getegid() from leavembox.c & lock.c
  88.  * They aren't even used there.
  89.  * From: tom@osf.org
  90.  *
  91.  * Revision 5.2  1992/10/17  22:18:36  syd
  92.  * Correct reversed usage of $d_utimbuf.
  93.  * From: chip@tct.com (Chip Salzenberg)
  94.  *
  95.  * Revision 5.1  1992/10/03  22:58:40  syd
  96.  * Initial checkin as of 2.4 Release at PL0
  97.  *
  98.  *
  99.  ******************************************************************************/
  100.  
  101. /** leave current folder, updating etc. as needed...
  102.   
  103. **/
  104.  
  105. #include "headers.h"
  106. #include "s_elm.h"
  107. #include <sys/stat.h>
  108. #ifdef USE_FLOCK_LOCKING
  109. #define SYSCALL_LOCKING
  110. #endif
  111. #ifdef USE_FCNTL_LOCKING
  112. #define SYSCALL_LOCKING
  113. #endif
  114. #ifdef SYSCALL_LOCKING
  115. #  if (defined(BSD) || !defined(apollo))
  116. #    include <sys/file.h>
  117. #  endif
  118. #endif
  119. #include <errno.h>
  120. #ifdef I_TIME
  121. #  include <time.h>
  122. #endif
  123. #ifdef I_SYSTIME
  124. #  include <sys/time.h>
  125. #endif
  126. #ifdef I_UTIME
  127. #  include <utime.h>
  128. #endif
  129. #ifdef I_SYSUTIME
  130. #  include <sys/utime.h>
  131. #endif
  132.  
  133.  
  134. /**********
  135.    Since a number of machines don't seem to bother to define the utimbuf
  136.    structure for some *very* obscure reason.... 
  137.  
  138.    Suprise, though, BSD has a different utime() entirely...*sigh*
  139. **********/
  140.  
  141. #ifndef BSD
  142. # ifndef UTIMBUF
  143.  
  144. struct utimbuf {
  145.     time_t    actime;        /** access time       **/ 
  146.     time_t    modtime;    /** modification time **/
  147.        };
  148.  
  149. # endif /* UTIMBUF */
  150. #endif /* BSD */
  151.  
  152. extern int errno;
  153.  
  154. char *error_description();
  155.  
  156. int
  157. leave_mbox(resyncing, quitting, prompt)
  158. int resyncing, quitting, prompt;
  159. {
  160.     /** Close folder, deleting some messages, storing others in mbox,
  161.         and keeping others, as directed by user input and elmrc options.
  162.  
  163.         Return    1    Folder altered
  164.             0    Folder not altered
  165.             -1    New mail arrived during the process and
  166.                     closing was aborted.
  167.         If "resyncing" we are just writing out folder to reopen it. We
  168.         therefore only consider deletes and keeps, not stores to mbox.
  169.         Also we don't remove NEW status so that it can be preserved
  170.         across the resync.
  171.  
  172.         If "quitting" and "prompt" is false, then no prompting is done.
  173.         Otherwise prompting is dependent upon the variable
  174.         question_me, as set by an elmrc option.  This behavior makes
  175.         the 'q' command prompt just like 'c' and '$', while
  176.         retaining the 'Q' command for a quick exit that never
  177.         prompts.
  178.     **/
  179.  
  180.     FILE *temp;
  181.     char temp_keep_file[SLEN], buffer[SLEN];
  182.     struct stat    buf;        /* stat command  */
  183. #ifdef SYMLINK
  184.     struct stat    lbuf;        /* lstat command  */
  185. #endif
  186. #if defined(BSD) && !defined(UTIMBUF)
  187.     time_t utime_buffer[2];        /* utime command */
  188. #else
  189.     struct utimbuf utime_buffer;    /* utime command */
  190. #endif
  191.     register int to_delete = 0, to_store = 0, to_keep = 0, i,
  192.              marked_deleted, marked_read, marked_unread,
  193.              last_sortby, ask_questions,  asked_storage_q,
  194.              num_chgd_status, need_to_copy, no_restore = FALSE;
  195.     char answer;
  196.     int  err;
  197.     long bytes();
  198.  
  199.     dprint(1, (debugfile, "\n\n-- leaving folder --\n\n"));
  200.  
  201.     if (message_count == 0)
  202.       return(0);    /* nothing changed */
  203.  
  204.     ask_questions = ((quitting && !prompt) ? FALSE : question_me);
  205.  
  206.     /* YES or NO on softkeys */
  207.     if (hp_softkeys && ask_questions) {
  208.       define_softkeys(YESNO);
  209.       softkeys_on();
  210.     }
  211.  
  212.     /* Clear the exit dispositions of all messages, just in case
  213.      * they were left set by a previous call to this function
  214.      * that was interrupted by the receipt of new mail.
  215.      */
  216.     for(i = 0; i < message_count; i++)
  217.       headers[i]->exit_disposition = UNSET;
  218.       
  219.     /* Determine if deleted messages are really to be deleted */
  220.  
  221.     /* we need to know if there are none, or one, or more to delete */
  222.     for (marked_deleted=0, i=0; i<message_count && marked_deleted<2; i++)
  223.       if (ison(headers[i]->status, DELETED))
  224.         marked_deleted++;
  225.  
  226.         if(marked_deleted) {
  227.       answer = (always_del ? *def_ans_yes : *def_ans_no);    /* default answer */
  228.       if(ask_questions) {
  229.         if (marked_deleted == 1)
  230.           MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveDeleteMessage,
  231.         "Delete message? (%c/%c) "), *def_ans_yes, *def_ans_no);
  232.         else
  233.           MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveDeleteMessages,
  234.         "Delete messages? (%c/%c) "), *def_ans_yes, *def_ans_no);
  235.         answer = want_to(buffer, answer, LINES-3, 0);
  236.       }
  237.  
  238.       if(answer == *def_ans_yes) {
  239.         for (i = 0; i < message_count; i++) {
  240.           if (ison(headers[i]->status, DELETED)) {
  241.         headers[i]->exit_disposition = DELETE;
  242.         to_delete++;
  243.           }
  244.         }
  245.       }
  246.     }
  247.     dprint(3, (debugfile, "Messages to delete: %d\n", to_delete));
  248.  
  249.     /* If this is a non spool file, or if we are merely resyncing,
  250.      * all messages with an unset disposition (i.e. not slated for
  251.      * deletion) are to be kept.
  252.      * Otherwise, we need to determine if read and unread messages
  253.      * are to be stored or kept.
  254.      */
  255.     if(folder_type == NON_SPOOL || resyncing) {
  256.       to_store = 0;
  257.       for (i = 0; i < message_count; i++) {
  258.         if(headers[i]->exit_disposition == UNSET) {
  259.           headers[i]->exit_disposition = KEEP;
  260.           to_keep++;
  261.         }
  262.       }
  263.     } else {
  264.  
  265.       /* Let's first see if user wants to store read messages 
  266.        * that aren't slated for deletion */
  267.  
  268.       asked_storage_q = FALSE;
  269.  
  270.       /* we need to know if there are none, or one, or more marked read */
  271.       for (marked_read=0, i=0; i < message_count && marked_read < 2; i++) {
  272.         if((isoff(headers[i]->status, UNREAD))
  273.           && (headers[i]->exit_disposition == UNSET))
  274.         marked_read++;
  275.       }
  276.       if(marked_read) {
  277.         answer = (always_store ? *def_ans_yes : *def_ans_no);    /* default answer */
  278.         if(ask_questions) {
  279.           if (marked_read == 1)
  280.         MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveMoveMessage,
  281.             "Move read message to \"received\" folder? (%c/%c) "),
  282.             *def_ans_yes, *def_ans_no);
  283.           else
  284.         MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveMoveMessages,
  285.             "Move read messages to \"received\" folder? (%c/%c) "),
  286.             *def_ans_yes, *def_ans_no);
  287.           answer = want_to(buffer, answer, LINES-3, 0);
  288.           asked_storage_q = TRUE;
  289.         }
  290.  
  291.         for (i = 0; i < message_count; i++) {
  292.           if((isoff(headers[i]->status, UNREAD)) 
  293.         && (headers[i]->exit_disposition == UNSET)) {
  294.  
  295.           if(answer == *def_ans_yes) {
  296.             headers[i]->exit_disposition = STORE;
  297.             to_store++;
  298.           } else {
  299.             headers[i]->exit_disposition = KEEP;
  300.             to_keep++;
  301.           }
  302.           }
  303.         } 
  304.       }
  305.  
  306.       /* If we asked the user if read messages should be stored,
  307.        * and if the user wanted them kept instead, then certainly the
  308.        * user would want the unread messages kept as well.
  309.        */
  310.       if(asked_storage_q && answer == *def_ans_no) {
  311.  
  312.         for (i = 0; i < message_count; i++) {
  313.           if((ison(headers[i]->status, UNREAD))
  314.         && (headers[i]->exit_disposition == UNSET)) {
  315.           headers[i]->exit_disposition = KEEP;
  316.           to_keep++;
  317.           }
  318.         }
  319.  
  320.       } else {
  321.  
  322.         /* Determine if unread messages are to be kept */
  323.  
  324.         /* we need to know if there are none, or one, or more unread */
  325.         for (marked_unread=0, i=0; i<message_count && marked_unread<2; i++)
  326.           if((ison(headers[i]->status, UNREAD))
  327.         && (headers[i]->exit_disposition == UNSET))
  328.           marked_unread++;
  329.  
  330.         if(marked_unread) {
  331.           answer = (always_keep ? *def_ans_yes : *def_ans_no);    /* default answer */
  332.           if(ask_questions) {
  333.         if (marked_unread == 1)
  334.           MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepMessage,
  335.             "Keep unread message in incoming mailbox? (%c/%c) "),
  336.             *def_ans_yes, *def_ans_no);
  337.         else
  338.           MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepMessages,
  339.             "Keep unread messages in incoming mailbox? (%c/%c) "),
  340.             *def_ans_yes, *def_ans_no);
  341.         answer = want_to(buffer, answer, LINES-3, 0);
  342.           }
  343.  
  344.           for (i = 0; i < message_count; i++) {
  345.         if((ison(headers[i]->status, UNREAD))
  346.           && (headers[i]->exit_disposition == UNSET)) {
  347.  
  348.             if(answer == *def_ans_no) {
  349.               headers[i]->exit_disposition = STORE;
  350.               to_store++;
  351.             } else {
  352.               headers[i]->exit_disposition = KEEP;
  353.               to_keep++;
  354.             }
  355.           
  356.         }
  357.           }
  358.         }
  359.       }
  360.     }
  361.  
  362.     dprint(3, (debugfile, "Messages to store: %d\n", to_store));
  363.     dprint(3, (debugfile, "Messages to keep: %d\n", to_keep));
  364.  
  365.     if(to_delete + to_store + to_keep != message_count) {
  366.       MoveCursor(LINES, 0);
  367.       Raw(OFF);
  368.       dprint(1, (debugfile,
  369.       "Error: %d to delete + %d to store + %d to keep != %d message cnt\n",
  370.         to_delete, to_store, to_keep, message_count));
  371.       printf(catgets(elm_msg_cat, ElmSet, ElmSomethingWrongInCounts,
  372.         "Something wrong in message counts! Folder unchanged.\n"));
  373.       emergency_exit();
  374.     }
  375.       
  376.  
  377.     /* If we are not resyncing, we are leaving the mailfile and
  378.      * the new messages are new no longer. Note that this changes
  379.      * their status.
  380.      */
  381.     if(!resyncing) {
  382.       for (i = 0; i < message_count; i++) {
  383.         if (ison(headers[i]->status, NEW)) {
  384.           clearit(headers[i]->status, NEW);
  385.           headers[i]->status_chgd = TRUE;
  386.         }
  387.       }
  388.     }
  389.  
  390.     /* If all messages are to be kept and none have changed status
  391.      * we don't need to do anything because the current folder won't
  392.      * be changed by our writing it out - unless we are resyncing, in
  393.      * which case we force the writing out of the mailfile.
  394.      */
  395.  
  396.     for (num_chgd_status = 0, i = 0; i < message_count; i++)
  397.       if(headers[i]->status_chgd == TRUE)
  398.         num_chgd_status++;
  399.     
  400.     if(!to_delete && !to_store && !num_chgd_status && !resyncing) {
  401.       dprint(3, (debugfile, "Folder keep as is!\n"));
  402.       error(catgets(elm_msg_cat, ElmSet, ElmFolderUnchanged,
  403.         "Folder unchanged."));
  404.       return(0);
  405.     }
  406.  
  407.     /** we have to check to see what the sorting order was...so that
  408.         the order in which we write messages is the same as the order
  409.         of the messages originally.
  410.         We only need to do this if there are any messages to be
  411.         written out (either to keep or to store). **/
  412.  
  413.     if ((to_keep || to_store ) && sortby != MAILBOX_ORDER) {
  414.       last_sortby = sortby;
  415.       sortby = MAILBOX_ORDER;
  416.       sort_mailbox(message_count, FALSE);
  417.       sortby = last_sortby;
  418.     }
  419.  
  420.     /* Formulate message as to number of keeps, stores, and deletes.
  421.      * This is only complex so that the message is good English.
  422.      */
  423.     if (to_keep > 0) {
  424.       if (to_store > 0) {
  425.         if (to_delete > 0) {
  426.           if (to_keep == 1)
  427.             MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepStoreDelete,
  428.               "[Keeping 1 message, storing %d, and deleting %d.]"), 
  429.             to_store, to_delete);
  430.           else
  431.             MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepStoreDeletePlural,
  432.               "[Keeping %d messages, storing %d, and deleting %d.]"), 
  433.             to_keep, to_store, to_delete);
  434.         } else {
  435.           if (to_keep == 1)
  436.         sprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepStore,
  437.             "[Keeping 1 message and storing %d.]"), 
  438.               to_store);
  439.           else
  440.         MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepStorePlural,
  441.             "[Keeping %d messages and storing %d.]"), 
  442.               to_keep, to_store);
  443.         }
  444.       } else {
  445.         if (to_delete > 0) {
  446.           if (to_keep == 1)
  447.         sprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepDelete,
  448.             "[Keeping 1 message and deleting %d.]"), 
  449.               to_delete);
  450.           else
  451.         MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepDeletePlural,
  452.             "[Keeping %d messages and deleting %d.]"), 
  453.               to_keep, to_delete);
  454.         } else {
  455.           if (to_keep == 1)
  456.         strcpy(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeep,
  457.             "[Keeping message.]"));
  458.           else
  459.         strcpy(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveKeepPlural,
  460.             "[Keeping all messages.]"));
  461.         }
  462.       }
  463.     } else if (to_store > 0) {
  464.       if (to_delete > 0) {
  465.         if (to_store == 1)
  466.           sprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveStoreDelete,
  467.               "[Storing 1 message and deleting %d.]"), 
  468.             to_delete);
  469.         else
  470.           MCsprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveStoreDeletePlural,
  471.               "[Storing %d messages and deleting %d.]"), 
  472.             to_store, to_delete);
  473.       } else {
  474.         if (to_store == 1)
  475.           strcpy(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveStore,
  476.               "[Storing message.]"));
  477.         else
  478.           strcpy(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveStorePlural,
  479.               "[Storing all messages.]"));
  480.       }
  481.     } else {
  482.       if (to_delete > 0)
  483.         strcpy(buffer, catgets(elm_msg_cat, ElmSet, ElmLeaveDelete,
  484.         "[Deleting all messages.]"));
  485.       else
  486.         buffer[0] = '\0';
  487.     }
  488.     /* NOTE: don't use variable "buffer" till message is output later */
  489.  
  490.     /** next, let's lock the file up and make one last size check **/
  491.  
  492.     if (folder_type == SPOOL)
  493.       lock(OUTGOING);
  494.     
  495.     if (mailfile_size != bytes(cur_folder)) {
  496.       unlock();
  497.       error(catgets(elm_msg_cat, ElmSet, ElmLeaveNewMailArrived,
  498.         "New mail has just arrived. Resynchronizing..."));
  499.       return(-1);
  500.     }
  501.     
  502.     /* Everything's GO - so ouput that user message and go to it. */
  503.  
  504.     block_signals();
  505.     
  506.     dprint(2, (debugfile, "Action: %s\n", buffer));
  507.     error(buffer);
  508.  
  509.     /* Store messages slated for storage in received mail folder */
  510.     if (to_store > 0) {
  511.       if ((err = can_open(recvd_mail, "a"))) {
  512.         error1(catgets(elm_msg_cat, ElmSet, ElmLeaveAppendDenied,
  513.           "Permission to append to %s denied!  Leaving folder intact.\n"),
  514.           recvd_mail);
  515.         dprint(1, (debugfile,
  516.           "Error: Permission to append to folder %s denied!! (%s)\n",
  517.           recvd_mail, "leavembox"));
  518.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  519.         unlock();
  520.         unblock_signals();
  521.         return(0);
  522.       }
  523.       if ((temp = fopen(recvd_mail,"a")) == NULL) {
  524.         err = errno;
  525.         unlock();
  526.         MoveCursor(LINES, 0);
  527.         Raw(OFF);
  528.         dprint(1, (debugfile, "Error: could not append to file %s\n", 
  529.           recvd_mail));
  530.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  531.         printf(catgets(elm_msg_cat, ElmSet, ElmLeaveCouldNotAppend,
  532.         "Could not append to folder %s!\n"), recvd_mail);
  533.         emergency_exit();
  534.       }
  535.       dprint(2, (debugfile, "Storing message%s ", plural(to_store)));
  536.       for (i = 0; i < message_count; i++) {
  537.         if(headers[i]->exit_disposition == STORE) {
  538.           current = i+1;
  539.           dprint(2, (debugfile, "#%d, ", current));
  540.           copy_message("", temp, CM_UPDATE_STATUS);
  541.         }
  542.       }
  543.       fclose(temp);
  544.       dprint(2, (debugfile, "\n\n"));
  545.       chown(recvd_mail, userid, groupid);
  546.     }
  547.  
  548.     /* If there are any messages to keep, first copy them to a
  549.      * temp file, then remove original and copy whole temp file over.
  550.      */
  551.     if (to_keep > 0) {
  552.       sprintf(temp_keep_file, "%s%s%d", temp_dir, temp_file, getpid());
  553.       if ((err = can_open(temp_keep_file, "w"))) {
  554.         error1(catgets(elm_msg_cat, ElmSet, ElmLeaveTempFileDenied,
  555. "Permission to create temp file %s for writing denied! Leaving folder intact."),
  556.           temp_keep_file);
  557.         dprint(1, (debugfile,
  558.           "Error: Permission to create temp file %s denied!! (%s)\n",
  559.           temp_keep_file, "leavembox"));
  560.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  561.         unlock();
  562.         unblock_signals();
  563.         return(0);
  564.       }
  565.       if ((temp = fopen(temp_keep_file,"w")) == NULL) {
  566.         err = errno;
  567.         unlock();
  568.         MoveCursor(LINES, 0);
  569.         Raw(OFF);
  570.         dprint(1, (debugfile, "Error: could not create file %s\n", 
  571.           temp_keep_file));
  572.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  573.         printf(catgets(elm_msg_cat, ElmSet, ElmLeaveCouldNotCreate,
  574.         "Could not create temp file %s!\n"), temp_keep_file);
  575.         emergency_exit();
  576.       }
  577.       dprint(2, (debugfile, "Copying to temp file message%s to be kept ",
  578.         plural(to_keep)));
  579.       for (i = 0; i < message_count; i++) {
  580.         if(headers[i]->exit_disposition == KEEP) {
  581.           current = i+1;
  582.           dprint(2, (debugfile, "#%d, ", current));
  583.           copy_message("", temp, CM_UPDATE_STATUS);
  584.         }
  585.       }
  586.       if ( fclose(temp) == EOF ) {
  587.         MoveCursor(LINES, 0);
  588.         Raw(OFF);
  589.         printf(catgets(elm_msg_cat, ElmSet, ElmLeaveCloseFailedTemp,
  590.         "\nClose failed on temp keep file in leavembox\n"));
  591.         perror(temp_keep_file);
  592.         dprint(2, (debugfile, "\n\rfclose err on temp_keep_file - leavembox\n\r"));
  593.         rm_temps_exit();
  594.       }
  595.       dprint(2, (debugfile, "\n\n"));
  596.  
  597.     } else if (folder_type == NON_SPOOL && !keep_empty_files && !resyncing) {
  598.  
  599.       /* i.e. if no messages were to be kept and this is not a spool
  600.        * folder and we aren't keeping empty non-spool folders,
  601.        * simply remove the old original folder and that's it!
  602.        */
  603.       (void)unlink(cur_folder);
  604.       unblock_signals();
  605.       return(1);
  606.     }
  607.  
  608.     /* Otherwise we have some work left to do! */
  609.  
  610.     /* Get original permissions and access time of the original
  611.      * mail folder before we remove it.
  612.      */
  613.     if(save_file_stats(cur_folder) != 0) {
  614.       error1(catgets(elm_msg_cat, ElmSet, ElmLeaveProblemsSavingPerms,
  615.         "Problems saving permissions of folder %s!"), cur_folder);
  616.       if (sleepmsg > 0)
  617.         sleep(sleepmsg);
  618.     }
  619.       
  620.         if (stat(cur_folder, &buf) != 0) {
  621.       err = errno;
  622.       dprint(1, (debugfile, "Error: errno %s attempting to stat file %s\n", 
  623.              error_description(err), cur_folder));
  624.           error2(catgets(elm_msg_cat, ElmSet, ElmLeaveErrorOnStat,
  625.         "Error %s on stat(%s)."), error_description(err), cur_folder);
  626.     }
  627.  
  628. #ifdef SYMLINK
  629.         if (lstat(cur_folder, &lbuf) != 0) {
  630.       err = errno;
  631.       dprint(1, (debugfile, "Error: errno %s attempting to stat file %s\n", 
  632.              error_description(err), cur_folder));
  633.           error2(catgets(elm_msg_cat, ElmSet, ElmLeaveErrorOnStat,
  634.         "Error %s on stat(%s)."), error_description(err), cur_folder);
  635.     }
  636. #endif
  637.  
  638.     /* Close and remove the original folder.
  639.      * However, if we are going to copy a temp file of kept messages
  640.      * to it, and this is a locked (spool) mailbox, we need to keep
  641.      * it locked during this process. Unfortunately,
  642.      * if we did our USE_FLOCK_LOCKING or USE_FCNTL_LOCKING unlinking
  643.      * the original will kill the lock, so we have to resort to copying
  644.      * the temp file to the original file while keeping the original open.
  645.      * Also, if the file has a link count > 1, then it has links, so to
  646.      * prevent destroying the links, we do a copy back, even though its
  647.      * slower.  If the file is a symlink, then we also need to do a copy
  648.      * back to prevent destroying the linkage.
  649.      */
  650.  
  651.     /*
  652.      * fclose(mailfile);
  653.      *
  654.      * While this fclose is OK for BSD flock file locking, it is
  655.      * incorrect for SYSV fcntl file locking.  For some reason AT&T
  656.      * decided to release all file locks when *any* fd to a file
  657.      * is closed, even if it is not the fd that acquired the lock.
  658.      * Thus this fclose would release the mailbox file locks.
  659.      * Instead I am going to just fflush the file here, and do the
  660.      * individual closes in the subcases to ensure that the
  661.      * mailbox is locked until we are finished with it.
  662.      */
  663.     fflush(mailfile);
  664.  
  665.     if(to_keep) {
  666. #ifdef SYSCALL_LOCKING
  667.       need_to_copy = (folder_type == SPOOL ? TRUE : FALSE);
  668. #else
  669.       need_to_copy = FALSE;
  670. #endif /* SYSCALL_LOCKING */
  671.  
  672.       if (buf.st_nlink > 1)
  673.         need_to_copy = TRUE;
  674.  
  675.       if (buf.st_mode & 0x7000) { /* copy if special modes set */
  676.          need_to_copy = TRUE;    /* such as enforcement lock */
  677.          no_restore = TRUE;
  678.       }
  679.  
  680. #ifdef SYMLINK
  681. #ifdef S_ISLNK
  682.       if (S_ISLNK(lbuf.st_mode))
  683. #else
  684.       if ((lbuf.st_mode & S_IFMT) == S_IFLNK)
  685. #endif
  686.       {
  687.          need_to_copy = TRUE;
  688.          no_restore = TRUE;
  689.       }
  690. #endif
  691.  
  692. #ifdef SAVE_GROUP_MAILBOX_ID
  693.       if (folder_type == SPOOL)
  694.               setgid(mailgroupid);
  695. #endif
  696.  
  697.       if(!need_to_copy) {
  698.         unlink(cur_folder);
  699.         if (link(temp_keep_file, cur_folder) != 0) {
  700.           if(errno == EXDEV || errno == EEXIST) {
  701.         /* oops - can't link across file systems - use copy instead */
  702.         need_to_copy = TRUE;
  703.           } else {
  704.         err = errno;
  705.         MoveCursor(LINES, 0);
  706.         Raw(OFF);
  707.         dprint(1, (debugfile, "link(%s, %s) failed (leavembox)\n", 
  708.                temp_keep_file, cur_folder));
  709.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  710.         printf(catgets(elm_msg_cat, ElmSet, ElmLeaveLinkFailed,
  711.             "Link failed! %s.\n"), error_description(err));
  712. #ifdef SAVE_GROUP_MAILBOX_ID
  713.             if (folder_type == SPOOL)
  714.           setgid(groupid);
  715. #endif
  716.         unlock();
  717.         fclose(mailfile);
  718.         emergency_exit();
  719.           }
  720.         }
  721.       }
  722.  
  723.       if(need_to_copy) {
  724.  
  725.         if (copy(temp_keep_file, cur_folder) != 0) {
  726.  
  727.           /* copy to cur_folder failed - try to copy to special file */
  728.           err = errno;
  729.           dprint(1, (debugfile, "leavembox: copy(%s, %s) failed;",
  730.               temp_keep_file, cur_folder));
  731.           dprint(1, (debugfile, "** %s **\n", error_description(err)));
  732.           error(catgets(elm_msg_cat, ElmSet, ElmLeaveCouldntModifyFolder,
  733.             "Couldn't modify folder!"));
  734.           if (sleepmsg > 0)
  735.             sleep((sleepmsg + 1) / 2);
  736.           sprintf(cur_folder,"%s/%s", home, unedited_mail);
  737.           if (copy(temp_keep_file, cur_folder) != 0) {
  738.  
  739.         /* couldn't copy to special file either */
  740.         err = errno;
  741.         MoveCursor(LINES, 0);
  742.         Raw(OFF);
  743.         dprint(1, (debugfile, 
  744.             "leavembox: couldn't copy to %s either!!  Help;", 
  745.             cur_folder));
  746.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  747.         printf(catgets(elm_msg_cat, ElmSet, ElmLeaveCantCopyMailbox,
  748.             "Can't copy folder, system trouble : contents preserved in %s\n"),temp_keep_file);
  749. #ifdef SAVE_GROUP_MAILBOX_ID
  750.             if (folder_type == SPOOL)
  751.           setgid(groupid);
  752. #endif
  753.         unlock();
  754.         fclose(mailfile);
  755.         emergency_exit();
  756.           } else {
  757.         dprint(1, (debugfile,
  758.             "\nWoah! Confused - Saved mail in %s (leavembox)\n", 
  759.             cur_folder));
  760.         error1(catgets(elm_msg_cat, ElmSet, ElmLeaveSavedMailIn,
  761.             "Saved mail in %s."), cur_folder);
  762.         if (sleepmsg > 0)
  763.             sleep((sleepmsg + 1) / 2);
  764.           }
  765.         }
  766.       }
  767.  
  768.       /* link or copy complete - remove temp keep file */
  769.       unlink(temp_keep_file);
  770.  
  771.     } else if(folder_type == SPOOL || keep_empty_files || resyncing) {
  772.  
  773.       /* if this is an empty spool file, or if this is an empty non spool 
  774.        * file and we keep empty non spool files (we always keep empty
  775.        * spool files), create an empty file */
  776.  
  777.       if(folder_type == NON_SPOOL)
  778.         error1(catgets(elm_msg_cat, ElmSet, ElmLeaveKeepingEmpty,
  779.         "Keeping empty folder '%s'."), cur_folder);
  780.       temp = fopen(cur_folder, "w");
  781.       fclose(temp);
  782.     }
  783.  
  784.     /*
  785.      * restore permissions and access times of folder only if not
  786.      * a symlink, as symlinks have no permissions, and not worth
  787.      * tracking down what it points to.
  788.      */
  789.  
  790.     if (!no_restore) {
  791.       if(restore_file_stats(cur_folder) != 1) {
  792.         error1(catgets(elm_msg_cat, ElmSet, ElmLeaveProblemsRestoringPerms,
  793.           "Problems restoring permissions of folder %s!"), cur_folder);
  794.         if (sleepmsg > 0)
  795.         sleep(sleepmsg);
  796.       }
  797.     }
  798.  
  799. #if defined(BSD) && !defined(UTIMBUF)
  800.     utime_buffer[0]     = buf.st_atime;
  801.     utime_buffer[1]     = buf.st_mtime;
  802. #else
  803.     utime_buffer.actime = buf.st_atime;
  804.     utime_buffer.modtime= buf.st_mtime;
  805. #endif
  806.  
  807. #if defined(BSD) && !defined(UTIMBUF)
  808.     if (utime(cur_folder, utime_buffer) != 0) 
  809. #else
  810.     if (utime(cur_folder, &utime_buffer) != 0) 
  811. #endif
  812.     {
  813.       err = errno;
  814.       dprint(1, (debugfile, 
  815.          "Error: encountered error doing utime (leavmbox)\n"));
  816.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  817.       error2(catgets(elm_msg_cat, ElmSet, ElmLeaveChangingAccessTime,
  818.         "Error %s trying to change file %s access time."), 
  819.            error_description(err), cur_folder);
  820.     }
  821. #ifdef SAVE_GROUP_MAILBOX_ID
  822.     if (folder_type == SPOOL)
  823.         setgid(groupid);
  824. #endif
  825.  
  826.  
  827.     mailfile_size = bytes(cur_folder);
  828.     unlock();    /* remove the lock on the file ASAP! */
  829.     fclose(mailfile);
  830.     unblock_signals();
  831.     return(1);    
  832. }
  833.  
  834. #ifdef HASSIGPROCMASK
  835.     sigset_t    toblock, oldset;
  836. #else  /* HASSIGPROCMASK */
  837. #  ifdef HASSIGBLOCK
  838.     int        toblock, oldset;
  839. #  else /* HASSIGBLOCK */
  840. #    ifdef HASSIGHOLD
  841.     /* Nothing required */
  842. #    else /* HASSIGHOLD */
  843.     SIGHAND_TYPE    (*oldhup)();
  844.     SIGHAND_TYPE    (*oldint)();
  845.     SIGHAND_TYPE    (*oldquit)();
  846.     SIGHAND_TYPE    (*oldstop)();
  847. #    endif /* HASSIGHOLD */
  848. #  endif /* HASSIGBLOCK */
  849. #endif /* HASSIGPROCMASK */
  850.  
  851. /*
  852.  * Block all keyboard generated signals.  Need to do this while
  853.  * rewriting mailboxes to avoid inadvertant corruption.  In
  854.  * particular, a SIGHUP (from logging out under /bin/sh), can
  855.  * corrupt a spool mailbox during an elm autosync.
  856.  */
  857.  
  858. block_signals()
  859. {
  860.     dprint(1,(debugfile, "block_signals\n"));
  861. #ifdef HASSIGPROCMASK
  862.     sigemptyset(&oldset);
  863.     sigemptyset(&toblock);
  864.     sigaddset(&toblock, SIGHUP);
  865.     sigaddset(&toblock, SIGINT);
  866.     sigaddset(&toblock, SIGQUIT);
  867. #ifdef SIGTSTP
  868.     sigaddset(&toblock, SIGTSTP);
  869. #endif /* SIGTSTP */
  870.  
  871.     sigprocmask(SIG_BLOCK, &toblock, &oldset);
  872.  
  873. #else /* HASSIGPROCMASK */
  874. #  ifdef HASSIGBLOCK
  875.     toblock = sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT);
  876. #ifdef SIGTSTP
  877.     toblock |= sigmask(SIGTSTP);
  878. #endif /* SIGTSTP */
  879.  
  880.     oldset = sigblock(toblock);
  881.  
  882. #  else /* HASSIGBLOCK */
  883. #    ifdef HASSIGHOLD
  884.     sighold(SIGHUP);
  885.     sighold(SIGINT);
  886.     sighold(SIGQUIT);
  887. #ifdef SIGTSTP
  888.     sighold(SIGTSTP);
  889. #endif /* SIGTSTP */
  890.  
  891. #    else /* HASSIGHOLD */
  892.     oldhup  = signal(SIGHUP, SIG_IGN);
  893.     oldint  = signal(SIGINT, SIG_IGN);
  894.     oldquit = signal(SIGQUIT, SIG_IGN);
  895. #ifdef SIGTSTP
  896.     oldstop = signal(SIGTSTP, SIG_IGN);
  897. #endif /* SIGTSTP */
  898. #    endif /* HASSIGHOLD */
  899. #  endif /* HASSIGBLOCK */
  900. #endif /* HASSIGPROCMASK */
  901. }
  902.  
  903. /*
  904.  * Inverse of the previous function.  Restore keyboard generated
  905.  * signals.
  906.  */
  907. unblock_signals()
  908. {
  909.     dprint(1,(debugfile, "unblock_signals\n"));
  910. #ifdef HASSIGPROCMASK
  911.     sigprocmask(SIG_SETMASK, &oldset, (sigset_t *)0);
  912.  
  913. #else  /* HASSIGPROCMASK */
  914. #  ifdef HASSIGBLOCK
  915.     sigsetmask(oldset);
  916.  
  917. #  else /* HASSIGBLOCK */
  918. #    ifdef HASSIGHOLD
  919.     sigrelse(SIGHUP);
  920.     sigrelse(SIGINT);
  921.     sigrelse(SIGQUIT);
  922. #ifdef SIGTSTP
  923.     sigrelse(SIGTSTP);
  924. #endif /* SIGTSTP */
  925.  
  926. #    else /* HASSIGHOLD */
  927.     signal(SIGHUP, oldhup);
  928.     signal(SIGINT, oldint);
  929.     signal(SIGQUIT, oldquit);
  930. #ifdef SIGTSTP
  931.     signal(SIGTSTP, oldstop);
  932. #endif /* SIGTSTP */
  933.  
  934. #    endif /* HASSIGHOLD */
  935. #  endif /* HASSIGBLOCK */
  936. #endif /* HASSIGPROCMASK */
  937. }
  938.  
  939.